#include "Logic/SkeletalInstancedProxy.h"

#include "SkelotAnimCollection.h"
#include "SkelotComponent.h"
#include "Logic/SkeletalInstancedSubsystem.h"


void FSkeletalInstancedProxyAbstract::Initialize(const FSkeletalInstanceKey& Key, const UObject* WorldContext)
{
	InstanceKey.NumCustomDataFloats = NumCustomDataFloats();
	InstanceKey.Initialize(Key);
	if(!Key.SkeletalMesh)
	{
		UE_LOG(LogTemp, Error, TEXT("FSkeletalInstancedProxyAbstract::Initialize Error Empty SkeletalMesh"));
		return;
	}
	USkeletalInstancedSubsystem* Subsystem = USkeletalInstancedSubsystem::Get(WorldContext);
	if(!Subsystem)
	{
		return;
	}
	SubsystemWeaker = Subsystem;
	USkelotAnimCollection* AnimCollection = Subsystem->FindAnimCollection(Key.SkeletalMesh->GetSkeleton());
	if(AnimCollection)
	{
		if(AnimCollection->Sequences.Num() > 0)
		{
			DefaultAnimSequence = AnimCollection->Sequences[0].Sequence;
		}
		AnimCollectionWeaker = AnimCollection;
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("FSkeletalInstancedProxyAbstract::Initialize Error AnimCollection %s"), *Key.SkeletalMesh->GetName());
	}
	Subsystem->Register(this);
	USkelotComponent* Component = Subsystem->FindComponent(this);
	if(!Component)
	{
		return;
	}
	Component->SetAnimCollection(AnimCollection);
	SkelotComponentWeaker = Component;


}

USkelotComponent* FSkeletalInstancedProxyAbstract::GetComponent() const
{
	return SkelotComponentWeaker.Get();
}

USkelotAnimCollection* FSkeletalInstancedProxyAbstract::GetAnimCollection() const
{
	return AnimCollectionWeaker.Get();
}

void FSkeletalInstancedProxyAbstract::BeginDestroy()
{
	if(USkeletalInstancedSubsystem* Subsystem = SubsystemWeaker.Get())
	{
		Subsystem->UnRegister(this);
	}
}

void FSkeletalInstancedProxyAbstract::RemoveInstance(int32 InstanceIndex)
{
	if(USkelotComponent* Component = SkelotComponentWeaker.Get())
	{
		if(Component->IsInstanceValid(InstanceIndex))
		{
			Component->DestroyInstance(InstanceIndex);
		}
	}
}

int32 FSkeletalInstancedProxyAbstract::AddInstance(const FTransform3f& WorldTransform, float InWeight)
{
	if(USkelotComponent* Component = SkelotComponentWeaker.Get())
	{
		const int32 Index = Component->AddInstance(WorldTransform, InWeight);
		//if(auto Sequence = DefaultAnimSequence.Get())
		//{
		//	Component->InstancePlayAnimation(Index, DefaultAnimSequence.Get(), true);
		//}
		//Component->InstanceAttachSubmeshByAsset(Index, GetSkeletalMesh(), true);
 		return Index;
	}
	return -1;
}

void FSkeletalInstancedProxyAbstract::SetInstanceTransform(int InstanceIndex, const FTransform3f& WorldTransform)
{
	if(USkelotComponent* Component = SkelotComponentWeaker.Get(); Component && Component->IsInstanceValid(InstanceIndex))
	{
		Component->SetInstanceTransform(InstanceIndex, WorldTransform);
	}
}

void FSkeletalInstancedProxyAbstract::PlayAnimation(int InstanceIndex, const FSoftObjectPath& InAnimation, const FSkelotAnimPlayParams& Params)
{
	if(UAnimSequenceBase* AnimSequenceBase = Cast<UAnimSequenceBase>( InAnimation.TryLoad() ))
	{
		PlayAnimation(InstanceIndex, AnimSequenceBase, Params);
	}
}

void FSkeletalInstancedProxyAbstract::PlayAnimation(int InstanceIndex, UAnimSequenceBase* InAnimation, const FSkelotAnimPlayParams& Params)
{
	if(!InAnimation)
	{
		UE_LOG(LogTemp, Error, TEXT("FSkeletalInstancedProxyAbstract::PlayAnimation Empty"))
		return;
	}
	if(USkelotComponent* Component = SkelotComponentWeaker.Get(); Component && Component->IsInstanceValid(InstanceIndex))
	{
		if(Component->AnimCollection)
		{
			Component->InstancePlayAnimation(InstanceIndex, InAnimation, Params);
		}
	}
}

FTransform3f FSkeletalInstancedProxyAbstract::GetInstanceSocketTransform(int InstanceIndex, FName SocketName, bool bWorldSpace) const
{
	if(USkelotComponent* Component = SkelotComponentWeaker.Get(); Component && Component->IsInstanceValid(InstanceIndex))
	{
		return Component->GetInstanceSocketTransform(InstanceIndex, SocketName, nullptr, bWorldSpace);
	}
	return FTransform3f::Identity;
}

//-------------------------FSkeletalInstancedProxy
FSkeletalInstancedProxy::FSkeletalInstancedProxy()
{
	AnimPlayParams.bIgnoreTransitionGeneration = true;
}

void FSkeletalInstancedProxy::PlayAnimSequence(const FSoftObjectPath& InAnimation)
{
	if(InstanceIndex < 0)
	{
		return;
	}
	PlayAnimation(InstanceIndex, InAnimation, AnimPlayParams);
}

void FSkeletalInstancedProxy::PlayAnimSequence(UAnimSequenceBase* InAnimation)
{
	if(InstanceIndex < 0)
	{
		return;
	}
	PlayAnimation(InstanceIndex, InAnimation, AnimPlayParams);
}

void FSkeletalInstancedProxy::UpdateTransform(const FTransform3f& WorldTransform)
{
	if(InstanceIndex < 0)
	{
		InstanceIndex = AddInstance(WorldTransform);
		return;
	}
	SetInstanceTransform(InstanceIndex, WorldTransform);
}

FTransform3f FSkeletalInstancedProxy::GetSocketTransform(FName SocketName, bool bWorldSpace) const
{
	return GetInstanceSocketTransform(InstanceIndex, SocketName, bWorldSpace);
}

void FSkeletalInstancedProxy::Remove()
{
	if(InstanceIndex < 0)
	{
		return;
	}
	RemoveInstance(InstanceIndex);
	InstanceIndex = -1;
}
